"""
Error handling framework for CodeMCP.

Provides centralized error handling, logging, and exception management
for all CodeMCP components.
"""

import logging
import traceback
from typing import Dict, Any, Optional
from enum import Enum
import json
from datetime import datetime


class ErrorLevel(Enum):
    """Error severity levels."""
    DEBUG = "debug"
    INFO = "info"
    WARNING = "warning"
    ERROR = "error"
    CRITICAL = "critical"


class CodeMCPError(Exception):
    """Base exception class for CodeMCP errors."""
    
    def __init__(self, message: str, error_code: str = None, details: Dict[str, Any] = None):
        super().__init__(message)
        self.message = message
        self.error_code = error_code or "CODEMCP_ERROR"
        self.details = details or {}
        self.timestamp = datetime.utcnow().isoformat()
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert error to dictionary format."""
        return {
            "error_code": self.error_code,
            "message": self.message,
            "details": self.details,
            "timestamp": self.timestamp,
            "type": self.__class__.__name__
        }


class ConfigurationError(CodeMCPError):
    """Configuration-related errors."""
    
    def __init__(self, message: str, config_key: str = None, **kwargs):
        super().__init__(message, "CONFIG_ERROR", **kwargs)
        if config_key:
            self.details["config_key"] = config_key


class AnalysisError(CodeMCPError):
    """Analysis-related errors."""
    
    def __init__(self, message: str, file_path: str = None, language: str = None, **kwargs):
        super().__init__(message, "ANALYSIS_ERROR", **kwargs)
        if file_path:
            self.details["file_path"] = file_path
        if language:
            self.details["language"] = language


class ParseError(CodeMCPError):
    """Parsing-related errors."""
    
    def __init__(self, message: str, line_number: int = None, column: int = None, **kwargs):
        super().__init__(message, "PARSE_ERROR", **kwargs)
        if line_number:
            self.details["line_number"] = line_number
        if column:
            self.details["column"] = column


class MCPCommunicationError(CodeMCPError):
    """MCP protocol communication errors."""
    
    def __init__(self, message: str, mcp_server: str = None, **kwargs):
        super().__init__(message, "MCP_COMM_ERROR", **kwargs)
        if mcp_server:
            self.details["mcp_server"] = mcp_server


class ErrorHandler:
    """Centralized error handling and logging system."""
    
    def __init__(self, logger_name: str = "codemcp", log_level: str = "INFO"):
        self.logger = logging.getLogger(logger_name)
        self.setup_logging(log_level)
        self.error_counts = {}
        
    def setup_logging(self, log_level: str):
        """Setup logging configuration."""
        # Create formatter
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        
        # Create console handler
        console_handler = logging.StreamHandler()
        console_handler.setFormatter(formatter)
        
        # Set log level
        level = getattr(logging, log_level.upper(), logging.INFO)
        self.logger.setLevel(level)
        console_handler.setLevel(level)
        
        # Add handler to logger
        if not self.logger.handlers:
            self.logger.addHandler(console_handler)
    
    def handle_error(self, error: Exception, context: Dict[str, Any] = None) -> Dict[str, Any]:
        """
        Handle an error with appropriate logging and formatting.
        
        Args:
            error: The exception to handle
            context: Additional context information
            
        Returns:
            Formatted error response
        """
        # Increment error count
        error_type = type(error).__name__
        self.error_counts[error_type] = self.error_counts.get(error_type, 0) + 1
        
        # Create error response
        if isinstance(error, CodeMCPError):
            error_response = error.to_dict()
        else:
            error_response = {
                "error_code": "UNEXPECTED_ERROR",
                "message": str(error),
                "details": {
                    "type": error_type,
                    "traceback": traceback.format_exc()
                },
                "timestamp": datetime.utcnow().isoformat()
            }
        
        # Add context if provided
        if context:
            error_response["context"] = context
        
        # Log the error
        self.log_error(error_response)
        
        return error_response
    
    def log_error(self, error_response: Dict[str, Any]):
        """Log error response with appropriate level."""
        error_code = error_response.get("error_code", "UNKNOWN")
        message = error_response.get("message", "Unknown error")
        
        # Determine log level based on error code
        if error_code.startswith("CONFIG_"):
            self.logger.error(f"Configuration Error: {message}")
        elif error_code.startswith("ANALYSIS_"):
            self.logger.warning(f"Analysis Error: {message}")
        elif error_code.startswith("PARSE_"):
            self.logger.warning(f"Parse Error: {message}")
        elif error_code.startswith("MCP_"):
            self.logger.error(f"MCP Communication Error: {message}")
        else:
            self.logger.error(f"Unexpected Error: {message}")
        
        # Log details if available
        if error_response.get("details"):
            self.logger.debug(f"Error details: {json.dumps(error_response['details'], indent=2)}")
    
    def log_info(self, message: str, context: Dict[str, Any] = None):
        """Log informational message."""
        self.logger.info(message)
        if context:
            self.logger.debug(f"Context: {json.dumps(context, indent=2)}")
    
    def log_warning(self, message: str, context: Dict[str, Any] = None):
        """Log warning message."""
        self.logger.warning(message)
        if context:
            self.logger.debug(f"Context: {json.dumps(context, indent=2)}")
    
    def log_debug(self, message: str, context: Dict[str, Any] = None):
        """Log debug message."""
        self.logger.debug(message)
        if context:
            self.logger.debug(f"Context: {json.dumps(context, indent=2)}")
    
    def get_error_statistics(self) -> Dict[str, Any]:
        """Get error statistics."""
        return {
            "error_counts": self.error_counts.copy(),
            "total_errors": sum(self.error_counts.values()),
            "error_types": list(self.error_counts.keys())
        }
    
    def reset_statistics(self):
        """Reset error statistics."""
        self.error_counts.clear()


# Global error handler instance
_global_error_handler = None


def get_error_handler() -> ErrorHandler:
    """Get the global error handler instance."""
    global _global_error_handler
    if _global_error_handler is None:
        _global_error_handler = ErrorHandler()
    return _global_error_handler


def handle_error(error: Exception, context: Dict[str, Any] = None) -> Dict[str, Any]:
    """Convenience function to handle errors using global handler."""
    return get_error_handler().handle_error(error, context)


def log_info(message: str, context: Dict[str, Any] = None):
    """Convenience function to log info using global handler."""
    get_error_handler().log_info(message, context)


def log_warning(message: str, context: Dict[str, Any] = None):
    """Convenience function to log warning using global handler."""
    get_error_handler().log_warning(message, context)


def log_debug(message: str, context: Dict[str, Any] = None):
    """Convenience function to log debug using global handler."""
    get_error_handler().log_debug(message, context)